package wci.frontend.pascal;

import static wci.message.MessageType.PARSER_SUMMARY;

import java.io.IOException;
import java.util.EnumSet;

import wci.frontend.EofToken;
import wci.frontend.Parser;
import wci.frontend.Scanner;
import wci.frontend.Token;
import wci.frontend.pascal.parsers.BlockParser;
import wci.frontend.pascal.parsers.StatementParser;
import wci.intermediate.ICode;
import wci.intermediate.ICodeFactory;
import wci.intermediate.ICodeNode;
import wci.intermediate.SymTabEntry;
import wci.intermediate.symtabimpl.DefinitionImpl;
import wci.intermediate.symtabimpl.Predefined;
import wci.intermediate.symtabimpl.SymTabKeyImpl;
import wci.message.Message;

/**
 * <h1>PascalParserTD</h1>
 * 
 * <p>
 * Top-Down模式的Pascal Parser，Pascal解析器的基类
 * </p>
 * <p>
 * Copyright (c) 2009 by Ronald Mak<br>
 * For instructional purposes only. No warranties.
 * </p>
 */
public class PascalParserTD extends Parser {

	protected PascalErrorHandler errorHandler = new PascalErrorHandler();
	
	public PascalParserTD(Scanner scanner) {
		super(scanner);
	}

	/* 新增链条解析(Parser Chain) */
	public PascalParserTD(PascalParserTD parent) {
		super(parent.getScanner());
	}
	//待解析程序的名字
	private SymTabEntry routineId; 
	public SymTabEntry getRoutineId() {
		return routineId;
	}
	public void setRoutineId(SymTabEntry routineId) {
		this.routineId = routineId;
	}
	/**
	 * Pascal的解析过程，产生Pascal相关的iCode和symbol table
	 */
	public void parse() throws Exception {

		long startTime = System.currentTimeMillis();
		ICode iCode = ICodeFactory.createICode();
		//初始化预定义
		Predefined.initialize(symTabStack);
		 //先放一个占位名字，后面会更新
        routineId = symTabStack.enterLocal("DummyProgramName".toLowerCase());
        routineId.setDefinition(DefinitionImpl.PROGRAM);
        symTabStack.setProgramId(routineId);

        //每个程序都有自己的符号表，在层次1
        routineId.setAttribute(SymTabKeyImpl.ROUTINE_SYMTAB, symTabStack.push());
        routineId.setAttribute(SymTabKeyImpl.ROUTINE_ICODE, iCode);
        BlockParser blockParser = new BlockParser(this);
		try {
			Token token = nextToken();
			 // 一个程序由块开始
            ICodeNode rootNode = blockParser.parse(token, routineId);
            iCode.setRoot(rootNode);
            symTabStack.pop();
            
            token = currentToken();
            //一个程序以符号'.'结束
            if (token.getType() != PascalTokenType.DOT) {
                errorHandler.flag(token, PascalErrorCode.MISSING_PERIOD, this);
            }
			token = currentToken(); // 没意义，不过我还是放在这，尊重作者。
			// 发送编译摘要信息
			float elapsedTime = (System.currentTimeMillis() - startTime) / 1000f;
			sendMessage(new Message(PARSER_SUMMARY, new Number[] {
					token.getLineNumber(), getErrorCount(), elapsedTime }));
		} catch (IOException e) {
			errorHandler.abortTranslation(PascalErrorCode.IO_ERROR, this);
		}
	}

	public int getErrorCount() {
		return errorHandler.getErrorCount();
	}
	/**
	 * 同步解析器的当前token到集合所允许的Token
	 * @param syncSet 下一步有效的token集合
	 * @return 找到的某个有效的token
	 * @throws Exception
	 */
	public Token synchronize(EnumSet syncSet) throws Exception {
		Token token = currentToken();
		//如果当前token不在同步集合里，那么就需要跳跃到结合范围内的token。
		if (!syncSet.contains(token.getType())) {
			//报告一个解析错误然后继续往前解析
			errorHandler.flag(token, PascalErrorCode.UNEXPECTED_TOKEN, this);
			do {
				token = nextToken();
			} while (!(token instanceof EofToken)
					&& !syncSet.contains(token.getType()));
		}
		return token;
	}
}
